package pl.agh.pp.zephyr.web;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;

import pl.agh.pp.zephyr.integration.GkController;
import pl.agh.pp.zephyr.integration.McuController;
import pl.agh.pp.zephyr.logic.Engine;
import pl.agh.pp.zephyr.model.Gatekeeper;
import pl.agh.pp.zephyr.model.Host;
import pl.agh.pp.zephyr.model.Mcu;
import pl.agh.pp.zephyr.model.User;
import pl.agh.pp.zephyr.web.controlPanels.ControlPanel;
import pl.agh.pp.zephyr.web.controlPanels.GkControlPanel;
import pl.agh.pp.zephyr.web.controlPanels.McuControlPanel;
import pl.agh.pp.zephyr.web.controlPanels.UserControlPanel;

@ManagedBean(name = "tabs")
@SessionScoped
public class Tabs implements Serializable {

	private static final long serialVersionUID = 5869830961828211909L;
	private int tabIndex = -1;
	private List<Tab> tabs = new ArrayList<Tab>();

	@ManagedProperty(value = "#{engine}")
	private Engine engine;

	public void removeTab(Tab tab) {
		// remove the specified tab index if possible.
		if (tabs != null) {
			tabs.remove(tab);
			// try and fine a valid index
			if (tabIndex > 0) {
				tabIndex--;
			}
		}
	}

	/**
	 * add a new tab to the panelTabSet.
	 * 
	 * @param event
	 *            add button click.
	 */
	private void addTab(int hash) {

		Object c = engine.area.getElement(hash);

		if (c == null) {
			return;
		}

		PushLogger pl = null;
		ControlPanel panel = null;
		if (c instanceof Gatekeeper) {
			GkController gkc = ((Gatekeeper) c).controller;
			panel = (ControlPanel) FacesFactory
					.getManagedBean("gkControlPanel");
			((GkControlPanel) panel).setController(gkc);
			// zawsze nowy pushLogger
			pl = (PushLogger) FacesFactory.getManagedBean("pushLogger");
			gkc.addHandler(pl);
		} else if (c instanceof Mcu) {
			McuController m = ((Mcu) c).controller;
			panel = (ControlPanel) FacesFactory
					.getManagedBean("mcuControlPanel");
			((McuControlPanel) panel).setController(m);
		} else if (c instanceof User) {
			panel = new UserControlPanel((User) c);
		} else {
			System.out.println("Tab with unknown controller: " + c.getClass()); // TODO
			return;
		}

		// set the new tab from the input
		Host h = (Host) c;
		final String title = (c instanceof Gatekeeper ? "Gatekeeper"
				: (c instanceof Mcu ? "MCU" : (c instanceof User ? ((User) c)
						.getAlias() : "Unknown")));
		Tab newTab = new Tab(title + " (" + h.ip + ":" + h.port + ")", pl,
				h.hashCode(), panel);

		// add to both tabs and select options of selectRadiobox
		tabs.add(newTab);
		tabIndex = tabs.size() - 1;
	}

	public List<Tab> getTabs() {
		for (Iterator<Tab> i = tabs.iterator(); i.hasNext();) {
			if (engine.area.getElement(i.next().id) == null) {
				i.remove();
			}
		}
		return tabs;
	}

	public int getTabIndex() {
		return tabIndex;
	}

	public int getTabsSize() {
		return tabs.size();
	}

	public void setTabIndex(int tabIndex) {
		this.tabIndex = tabIndex;
	}

	/**
	 * Inner class that represents a tab object with a label, content, and an
	 * index.
	 */
	public class Tab {
		String label;
		private final PushLogger pl;
		private final int id;
		private final ControlPanel panel;

		Tab(String label, PushLogger pl, int id, ControlPanel panel) {
			this.label = label;
			this.pl = pl;
			this.id = id;
			this.panel = panel;
		}

		public String getLabel() {
			return label.toString();
		}

		public void closeTab(ActionEvent event) {
			removeTab(this);
		}

		public PushLogger getPushLogger() {
			return pl;
		}

		public int getId() {
			return id;
		}

		public void setLabel(String label) {
			this.label = label;
		}

		public ControlPanel getPanel() {
			return panel;
		}
	}

	public void setEngine(Engine engine) {
		this.engine = engine;
	}

	public void openTab(int id) {
		for (int i = 0; i < tabs.size(); ++i) {
			Tab tab = tabs.get(i);
			if (tab.getId() == id) {
				setTabIndex(i);
				return;
			}
		}
		addTab(id);
	}
}
